///////////////////////////////////////////////////////////////////////////////
// Project     :  EseLinq http://code.google.com/p/eselinq/
// Copyright   :  (c) 2009 Christopher Smith
// Maintainer  :  csmith32@gmail.com
// Module      :  DemandLoadFunction - Support to access optional DLL functions on demand
///////////////////////////////////////////////////////////////////////////////
// 
//This software is licenced under the terms of the MIT License:
//
//Copyright (c) 2009 Christopher Smith
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in
//all copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
//THE SOFTWARE.
//
///////////////////////////////////////////////////////////////////////////////

template <class T> struct DemandLoadFunction
{
	PCWSTR Lib;
	PCSTR Name;
	T Func;
	DemandLoadFunction(PCWSTR Lib, PCSTR Name) :
		Lib(Lib),
		Name(Name),
		Func(NULL)
	{}

	void DemandQuiet()
	{
		if(!Func)
		{
			HMODULE Module = GetModuleHandle(Lib);

			if(Module)
				Func = reinterpret_cast<T>(GetProcAddress(Module, Name));
		}
	}

	void Demand()
	{
		HMODULE Module = GetModuleHandle(Lib);

		if(!Module)
			throw gcnew NotImplementedException(marshal_as<String ^>(Lib));

		Func = reinterpret_cast<T>(GetProcAddress(Module, Name));
		
		if(!Func)
			throw gcnew NotImplementedException(marshal_as<String ^>(Name));
	}

	operator T()
	{
		Demand();
		return Func;
	}
};